#include "stdafx.h"
#include "ColorShaderClass.h"


CColorShaderClass::CColorShaderClass(void) : m_pVertexShader(nullptr), m_pPixelShader(nullptr), m_pLayout(nullptr), m_pMatrixBuffer(nullptr)
{
}


CColorShaderClass::~CColorShaderClass(void)
{
}

bool CColorShaderClass::Initialize(ID3D11Device* pDevice, HWND hWnd)
{
	bool bResult = false;

	bResult = InitializeShader(pDevice, hWnd, L"Color.vs", L"Color.ps");
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize shader");
		return false;
	}

	return true;
}

void CColorShaderClass::ShutDown()
{
	ShutDownShader();
}

bool CColorShaderClass::Render(ID3D11DeviceContext* pDeviceContext, int nIndexCount, D3DXMATRIX d3dWorld, D3DXMATRIX d3dView, D3DXMATRIX d3dProj)
{
	bool bResult = false;

	bResult = SetShaderParameters(pDeviceContext, d3dWorld, d3dView, d3dProj);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to set shader parameters");
		return false;
	}

	RenderShader(pDeviceContext, nIndexCount);

	return true;
}

bool CColorShaderClass::InitializeShader(ID3D11Device* pDevice, HWND hWnd, WCHAR* pwszVSFileName, WCHAR* pwszPSFileName)
{
	HRESULT hResult;
	ID3D10Blob* pErrorMessage;
	ID3D10Blob* pVertexShaderBuffer;
	ID3D10Blob* pPixelShaderBuffer;
	D3D11_INPUT_ELEMENT_DESC stPolygonLayout[2];
	unsigned int uNumElements;
	D3D11_BUFFER_DESC stMatrixBufferDesc;

	pErrorMessage = nullptr;
	pVertexShaderBuffer = nullptr;
	pPixelShaderBuffer = nullptr;

	hResult = D3DX11CompileFromFile(pwszVSFileName, NULL, NULL, "ColorVertexShader", "vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, &pVertexShaderBuffer, &pErrorMessage, NULL);
	if(FAILED(hResult))
	{
		if(pErrorMessage != nullptr)
		{
			DEBUG_OUTPUT("Failed to compile vertex shader");			
			OutputShaderErrorMessage(pErrorMessage, hWnd, pwszVSFileName);
		}
		else
		{
			DEBUG_OUTPUT("Vertex shader not found");
		}

		return false;
	}

	hResult = D3DX11CompileFromFile(pwszPSFileName, NULL, NULL, "ColorPixelShader", "ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, &pPixelShaderBuffer, &pErrorMessage, NULL);
	if(FAILED(hResult))
	{
		if(pErrorMessage != nullptr)
		{
			DEBUG_OUTPUT("Failed to compile pixel shader");			
			OutputShaderErrorMessage(pErrorMessage, hWnd, pwszPSFileName);
		}
		else
		{
			DEBUG_OUTPUT("Pixel shader not found");
		}

		return false;
	}

	hResult = pDevice->CreateVertexShader(pVertexShaderBuffer->GetBufferPointer(), pVertexShaderBuffer->GetBufferSize(), NULL, &m_pVertexShader);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create Vertex Shader");
		return false;
	}

	hResult = pDevice->CreatePixelShader(pPixelShaderBuffer->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(), NULL, &m_pPixelShader);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create the Pixel Shader");
		return false;
	}

	stPolygonLayout[0].SemanticName = "POSITION";
	stPolygonLayout[0].SemanticIndex = 0;
	stPolygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
	stPolygonLayout[0].InputSlot = 0;
	stPolygonLayout[0].AlignedByteOffset = 0;
	stPolygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
	stPolygonLayout[0].InstanceDataStepRate = 0;

	stPolygonLayout[1].SemanticName = "COLOR";
	stPolygonLayout[1].SemanticIndex = 0;
	stPolygonLayout[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	stPolygonLayout[1].InputSlot = 0;
	stPolygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
	stPolygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
	stPolygonLayout[1].InstanceDataStepRate = 0;

	uNumElements = sizeof(stPolygonLayout) / sizeof(stPolygonLayout[0]);

	hResult = pDevice->CreateInputLayout(stPolygonLayout, uNumElements, pVertexShaderBuffer->GetBufferPointer(), pVertexShaderBuffer->GetBufferSize(), &m_pLayout);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create the input layput");
		return false;
	}

	pVertexShaderBuffer->Release();
	pVertexShaderBuffer = nullptr;

	pPixelShaderBuffer->Release();
	pPixelShaderBuffer = nullptr;

	stMatrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
	stMatrixBufferDesc.ByteWidth = sizeof(MatrixBufferType);
	stMatrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	stMatrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	stMatrixBufferDesc.MiscFlags = 0;
	stMatrixBufferDesc.StructureByteStride = 0;

	hResult = pDevice->CreateBuffer(&stMatrixBufferDesc, NULL, &m_pMatrixBuffer);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create Matrix buffer");
		return false;
	}

	return true;
}

void CColorShaderClass::ShutDownShader()
{
	if(m_pMatrixBuffer)
	{
		m_pMatrixBuffer->Release();
		m_pMatrixBuffer = 0;
	}

	if(m_pLayout)
	{
		m_pLayout->Release();
		m_pLayout = 0;
	}

	if(m_pPixelShader)
	{
		m_pPixelShader->Release();
		m_pPixelShader = 0;
	}

	if(m_pVertexShader)
	{
		m_pVertexShader->Release();
		m_pVertexShader = 0;
	}
}

void CColorShaderClass::OutputShaderErrorMessage(ID3D10Blob* pErrorMessage, HWND hWnd, WCHAR* pwszShaderFileName)
{
	char* cCompileErrors;
	unsigned long ulBufferSize;
	ofstream fout;

	cCompileErrors = (char*)(pErrorMessage->GetBufferPointer());

	ulBufferSize = pErrorMessage->GetBufferSize();

	fout.open("shader-error.txt");

	for(unsigned long i = 0; i < ulBufferSize; ++i)
	{
		fout << cCompileErrors[i];
	}

	fout.close();

	pErrorMessage->Release();
	pErrorMessage = nullptr;

	DEBUG_OUTPUT("Error compiling shaders. Check shader-error.txt for details");
}

bool CColorShaderClass::SetShaderParameters(ID3D11DeviceContext* pDeviceContext, D3DXMATRIX d3dWorld, D3DXMATRIX d3dView, D3DXMATRIX d3dProj)
{
	HRESULT hResult;
	D3D11_MAPPED_SUBRESOURCE stMappedResource;
	MatrixBufferType* pDataPtr;
	unsigned int nBufferNum;

	D3DXMatrixTranspose(&d3dWorld, &d3dWorld);
	D3DXMatrixTranspose(&d3dView, &d3dView);
	D3DXMatrixTranspose(&d3dProj, &d3dProj);

	hResult = pDeviceContext->Map(m_pMatrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &stMappedResource);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to map buffer");
		return false;
	}

	pDataPtr = (MatrixBufferType*)stMappedResource.pData;

	pDataPtr->d3dWorldMatrix = d3dWorld;
	pDataPtr->d3dViewMatrix = d3dView;
	pDataPtr->d3dProjectionMatrix = d3dProj;

	pDeviceContext->Unmap(m_pMatrixBuffer, 0);

	nBufferNum = 0;

	pDeviceContext->VSSetConstantBuffers(nBufferNum, 1, &m_pMatrixBuffer);

	return true;
}

void CColorShaderClass::RenderShader(ID3D11DeviceContext* pDeviceContext, int nIndexCount)
{
	pDeviceContext->IASetInputLayout(m_pLayout);

	pDeviceContext->VSSetShader(m_pVertexShader, NULL, 0);
	pDeviceContext->PSSetShader(m_pPixelShader, NULL, 0);

	pDeviceContext->DrawIndexed(nIndexCount, 0, 0);
}
